package org.larkdoc.controller;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.larkdoc.constant.DocConts;
import org.larkdoc.constant.ViewConts;
import org.larkdoc.model.bo.DocBO;
import org.larkdoc.model.entity.DocInfo;
import org.larkdoc.model.entity.DocRelProject;
import org.larkdoc.model.entity.UserInfo;
import org.larkdoc.model.vo.DocVO;
import org.larkdoc.model.vo.PageVO;
import org.larkdoc.model.vo.RespBaseVO;
import org.larkdoc.service.DocRelProjectService;
import org.larkdoc.service.DocService;
import org.larkdoc.service.ProjectService;
import org.larkdoc.service.UserService;
import org.larkdoc.util.AuthUtil;
import org.larkdoc.util.DozerUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.github.pagehelper.PageInfo;

/**
 * 文档控制类
 * 
 * @author  zhangpeijun[zhangpeijun1024@qq.com]
 * @version  [v1.0.1, 2017年10月17日]
 * @see  [相关类/方法]
 * @since  [产品/模块版本]
 */
@RestController
@RequestMapping("/doc")
public class DocController {
    
    private final static Logger log = LoggerFactory.getLogger(DocController.class);
    
    @Autowired
    DocService                  docService;
    
    @Autowired
    ProjectService              projectService;
    
    @Autowired
    UserService                 userService;
    
    @Autowired
    DocRelProjectService        docRelProjectService;
    
    @RequestMapping("/create")
    public RespBaseVO create(DocVO doc) {
        RespBaseVO respVo = new RespBaseVO();
        if (null != doc) {
            // TODO 如用户退出，会直接跳转到 主页，造成返回json有误。
            Subject subject = SecurityUtils.getSubject();
            if (subject.isAuthenticated()) {
                DocBO bo = DozerUtil.conversion(doc, DocBO.class);
                if (!docService.checkExists(bo, AuthUtil.getAccount())) {
                    bo.setCreator(AuthUtil.getAccount());
                    bo.setCreateTime(new Date());
                    bo.setUpdateTime(new Date());
                    String groIds = doc.getProjectIds();
                    if (StringUtils.isNotBlank(groIds)) {
                        String[] groIdsArr = groIds.split(",");
                        List<Integer> ids = new ArrayList<Integer>(groIdsArr.length);
                        for (String str : groIdsArr) {
                            try {
                                ids.add(Integer.valueOf(str));
                            } catch (NumberFormatException e) {
                                log.warn("id转型错误{}, 分割字符串={}", str, groIds);
                            }
                        }
                        ids = projectService.filterIds(ids);
                        if (CollectionUtils.isNotEmpty(ids)) {
                            List<DocRelProject> projects = new ArrayList<DocRelProject>(ids.size());
                            DocRelProject temp = null;
                            for (Integer id : ids) {
                                temp = new DocRelProject();
                                temp.setProjectId(id);
                                projects.add(temp);
                            }
                            bo.setProjectRelDocs(projects);
                        }
                    }
                    if (docService.insertDocBo(bo) > 0) {
                        respVo.setRetCode(ViewConts.Code.SUCCESS);
                        respVo.setRetMsg(ViewConts.Msg.SUCCESS);
                    }
                } else {
                    respVo.setRetCode(ViewConts.Code.FAILURE);
                    respVo.setRetMsg("项目已存在，请修改项目名称。");
                }
            } else {
                respVo.setRetCode(ViewConts.Code.USER_AUTHORIZATION_EXPIRE);
                respVo.setRetMsg(ViewConts.Msg.USER_AUTHORIZATION_EXPIRE);
            }
        } else {
            respVo.setRetCode(ViewConts.Code.PARAM_ERROR);
            respVo.setRetMsg(ViewConts.Msg.PARAM_ERROR);
        }
        return respVo;
    }
    
    @RequestMapping("/delete/{id}")
    public RespBaseVO delete(@PathVariable int id) {
        RespBaseVO respVo = new RespBaseVO();
        if (id > 0 && null != docService.getByIdAndAccount(id, AuthUtil.getAccount())) {
            // TODO 数据权限验证。
            if (docService.deleteByPrimaryKey(id) != 1) {
                respVo.setRetCode(ViewConts.Code.FAILURE);
                respVo.setRetMsg(ViewConts.Msg.FAILURE);
            }
        } else {
            respVo.setRetCode(ViewConts.Code.PARAM_ERROR);
            respVo.setRetMsg(ViewConts.Msg.PARAM_ERROR);
        }
        return respVo;
    }
    
    @RequestMapping("/delete/batch")
    public RespBaseVO deleteBatch(@RequestParam("ids[]") int[] ids) {
        RespBaseVO respVo = new RespBaseVO(ViewConts.Code.FAILURE, ViewConts.Msg.FAILURE, null);
        if (null != ids && ids.length > 0) {
            int result = docService.deleteByIdsAndAccount(ids, AuthUtil.getAccount());
            if (result > 0) {
                respVo.setRetCode(ViewConts.Code.SUCCESS);
                respVo.setRetMsg(ViewConts.Msg.SUCCESS);
                respVo.setRetVal("成功删除：" + result + " 条数据。");
            }
        } else {
            respVo.setRetVal("请求删除数据为空。");
        }
        return respVo;
    }
    
    @RequestMapping("/get/{id}")
    public RespBaseVO get(@PathVariable int id) {
        RespBaseVO result = new RespBaseVO();
        // 用户可查询其可见范围数据: 自己创建的，项目组的，对外开放的。
        DocBO doc = docService.getAuthDocById(id, AuthUtil.getAccount());
        if (null != doc) {
            DocVO vo = DozerUtil.conversion(doc, DocVO.class);
            // 屏蔽群成员信息
            vo.setProjects(null);
            result.setRetVal(vo);
        } else {
            result.setRetVal("无数据或没有查看权限。");
        }
        log.info("Result = {}", result);
        return result;
    }
    
    @RequestMapping("/update")
    public RespBaseVO update(DocVO doc) {
        RespBaseVO respVo = new RespBaseVO();
        // TODO 只支持用户更新自己帐号
        if (null != doc && doc.getId() > 0) {
            String account = AuthUtil.getAccount();
            DocInfo oldDoc = docService.getByIdAndAccount(doc.getId(), account);
            if (null != oldDoc) {
                // 替换可更新属性。
                oldDoc.setName(doc.getName());
                oldDoc.setTag(doc.getTag());
                oldDoc.setVisibleRange(doc.getVisibleRange());
                oldDoc.setDescription(doc.getDescription());
                oldDoc.setHtmlDetail(doc.getHtmlDetail());
                oldDoc.setMdDetail(doc.getMdDetail());
                oldDoc.setUpdateTime(new Date());
                oldDoc.setRemark(doc.getRemark());
                if (docService.updateByPrimaryKey(oldDoc) != 1) {
                    respVo.setRetCode(ViewConts.Code.FAILURE);
                    respVo.setRetMsg(ViewConts.Msg.FAILURE);
                } else {
                    if (DocConts.VisibleRange.PROJECT == oldDoc.getVisibleRange()) {
                        docRelProjectService.deleteByDocId(oldDoc.getId());
                        String groIds = doc.getProjectIds();
                        if (StringUtils.isNotBlank(groIds)) {
                            String[] groIdsArr = groIds.split(",");
                            List<Integer> ids = new ArrayList<Integer>(groIdsArr.length);
                            for (String str : groIdsArr) {
                                try {
                                    ids.add(Integer.valueOf(str));
                                } catch (NumberFormatException e) {
                                    log.warn("id转型错误{}, 分割字符串={}", str, groIds);
                                }
                            }
                            ids = projectService.filterIds(ids);
                            if (CollectionUtils.isNotEmpty(ids)) {
                                List<DocRelProject> projects = new ArrayList<DocRelProject>(ids.size());
                                DocRelProject temp = null;
                                for (Integer id : ids) {
                                    temp = new DocRelProject();
                                    temp.setProjectId(id);
                                    temp.setDocId(oldDoc.getId());
                                    projects.add(temp);
                                }
                                docRelProjectService.insertBatch(projects);
                            }
                        }
                    }
                }
            } else {
                log.info("{},用户无权限更新文档：{}", account, doc);
                respVo.setRetCode(ViewConts.Code.PARAM_ERROR);
                respVo.setRetMsg("用户无权限更新此文档.");
            }
        } else {
            respVo.setRetCode(ViewConts.Code.PARAM_ERROR);
            respVo.setRetMsg(ViewConts.Msg.PARAM_ERROR);
        }
        return respVo;
    }
    
    @RequestMapping("/update/get/{id}")
    public RespBaseVO updatePro(@PathVariable int id) {
        RespBaseVO result = new RespBaseVO();
        DocBO doc = docService.getAuthDocById(id, AuthUtil.getAccount());
        if (null != doc) {
            DocVO vo = DozerUtil.conversion(doc, DocVO.class);
            // TODO 考虑屏蔽项目组信息
            result.setRetVal(vo);
        } else {
            result.setRetCode(ViewConts.Code.FAILURE);
            result.setRetMsg(ViewConts.Msg.FAILURE);
            result.setRetVal("查无数据。");
        }
        return result;
    }
    
    @RequestMapping("/page")
    @ResponseBody
    public RespBaseVO page(PageVO<DocVO> page) {
        RespBaseVO respVo = new RespBaseVO();
        log.debug("page param {}", page);
        DocVO doc = null == page.getSearch() ? page.searchMapToTargetClass(DocVO.class) : page.getSearch();
        doc = null == doc ? new DocVO() : doc;
        // 获取开放文档时，不需要加入创建者
        if(DocConts.VisibleRange.OPEN == doc.getVisibleRange()){
            doc.setCreator(null);
        } else {
            if (StringUtils.isNotBlank(AuthUtil.getAccount())) {
                // 获取自己的和有权限的文件。
                doc.setCreator(AuthUtil.getAccount());
            } else {
                // 未登录,获取所有人可见文档
                doc.setVisibleRange(DocConts.VisibleRange.OPEN);
            }
        }
        page.setSearch(doc);
        PageInfo<DocBO> query = docService.pageBO(page);
        @SuppressWarnings("unchecked")
        PageVO<DocVO> result = DozerUtil.conversion(query, PageVO.class);
        result.setList(bo2Vo(query.getList()));
        respVo.setRetVal(result);
        return respVo;
    }
    
    @RequestMapping("/pageByProject")
    public RespBaseVO pageByProject(PageVO<DocVO> page) {
        RespBaseVO respVo = new RespBaseVO();
        log.debug("pageByProject param {}", page);
        DocVO doc = null == page.getSearch() ? page.searchMapToTargetClass(DocVO.class) : page.getSearch();
        if (doc != null && StringUtils.isNotBlank(doc.getProjectIds())) {
            String[] projectIds = doc.getProjectIds().split(",");
            List<Integer> projectIdList = new ArrayList<Integer>(projectIds.length);
            for (String id : projectIds) {
                projectIdList.add(Integer.valueOf(id));
            }
            doc.setProjectIdList(filterValidProject(projectIdList));
        } else {
            return page(page);
        }
        doc = null == doc ? new DocVO() : doc;
        page.setSearch(doc);
        PageInfo<DocBO> query = docService.pageByProject(page);
        @SuppressWarnings("unchecked")
        PageVO<DocVO> result = DozerUtil.conversion(query, PageVO.class);
        result.setList(bo2Vo(query.getList()));
        respVo.setRetVal(result);
        return respVo;
    }
    
    private List<Integer> filterValidProject(List<Integer> idsList) {
        List<Integer> result = null;
        String account = AuthUtil.getAccount();
        UserInfo user = userService.getByAccount(account);
        result = projectService.selectIdsByUser(null != user ? user.getId() : null, idsList, account);
        return result;
    }
    
    private List<DocVO> bo2Vo(List<DocBO> boList) {
        List<DocVO> result = null;
        if (CollectionUtils.isNotEmpty(boList)) {
            // TODO 需要屏蔽属性。
            result = DozerUtil.conversionList(boList, DocVO.class);
        }
        return result;
    }
    
}
